// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using System.CommandLine;
using System.Text.Json;
using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.NativeWrapper;
using EnvironmentProvider = Microsoft.DotNet.NativeWrapper.EnvironmentProvider;

namespace Microsoft.DotNet.Cli.Commands.Sdk.Check;

public class SdkCheckCommand : CommandBase
{
    private readonly INETBundleProvider _netBundleProvider;
    private readonly IReporter _reporter;
    private readonly IProductCollectionProvider _productCollectionProvider;
    private readonly string _dotnetPath;
    private readonly SdkCheckConfig _sdkCheckConfig;

    public SdkCheckCommand(
        ParseResult parseResult,
        INETBundleProvider bundleProvider = null,
        IProductCollectionProvider productCollectionProvider = null,
        IReporter reporter = null,
        string dotnetRoot = null,
        string dotnetVersion = null) : base(parseResult)
    {
        _dotnetPath = dotnetRoot ?? EnvironmentProvider.GetDotnetExeDirectory();
        var configFilePath = Path.Combine(_dotnetPath, "sdk", dotnetVersion ?? Product.Version, "sdk-check-config.json");
        _sdkCheckConfig = File.Exists(configFilePath) ? JsonSerializer.Deserialize<SdkCheckConfig>(File.ReadAllText(configFilePath)) : null;
        _reporter = reporter ?? Reporter.Output;
        _netBundleProvider = bundleProvider == null ? new NETBundlesNativeWrapper() : bundleProvider;
        _productCollectionProvider = productCollectionProvider == null ? new ProductCollectionProvider() : productCollectionProvider;
    }

    public override int Execute()
    {
        if (_sdkCheckConfig != null && !string.IsNullOrEmpty(_sdkCheckConfig.CommandOutputReplacementString))
        {
            _reporter.WriteLine();
            _reporter.WriteLine(_sdkCheckConfig.CommandOutputReplacementString);
            _reporter.WriteLine();
        }
        else
        {
            try
            {
                var productCollection = _productCollectionProvider.GetProductCollection(
                    _sdkCheckConfig?.ReleasesUri == null ? null : new Uri(_sdkCheckConfig.ReleasesUri),
                    _sdkCheckConfig?.ReleasesFilePath == null ? null : _sdkCheckConfig.ReleasesFilePath);
                var environmentInfo = _netBundleProvider.GetDotnetEnvironmentInfo(_dotnetPath);
                var sdkFormatter = new SdkOutputWriter(environmentInfo.SdkInfo, productCollection, _productCollectionProvider, _reporter);
                var runtimeFormatter = new RuntimeOutputWriter(environmentInfo.RuntimeInfo, productCollection, _productCollectionProvider, _reporter);

                sdkFormatter.PrintSdkInfo();
                _reporter.WriteLine();
                runtimeFormatter.PrintRuntimeInfo();
                _reporter.WriteLine();
                _reporter.WriteLine(CliCommandStrings.CommandFooter);
                _reporter.WriteLine();
            }
            catch (HostFxrResolutionException hostfxrResolutionException)
            {
                switch (hostfxrResolutionException)
                {
                    case HostFxrRuntimePropertyNotSetException:
                        throw new GracefulException([CliCommandStrings.RuntimePropertyNotFound], [], isUserError: false);

                    case HostFxrNotFoundException hostFxrNotFoundException:
                        throw new GracefulException([CliCommandStrings.HostFxrCouldNotBeLoaded], [hostFxrNotFoundException.Message], isUserError: false);
                }
            }
        }

        return 0;
    }

    public static int Run(ParseResult parseResult)
    {
        return new SdkCheckCommand(parseResult).Execute();
    }
}

internal class SdkCheckConfig
{
    public string ReleasesUri { get; set; }
    public string ReleasesFilePath { get; set; }
    public string CommandOutputReplacementString { get; set; }
}
